/******************************************************************************
秋夜静，独坐对残灯。
啼笑非非谁识我，坐行梦梦尽缘君，何所慰消沉。
风卷雨，雨复卷侬心。
心似欲随风雨去，茫茫大海任浮沉。
无爱亦无恨。
******************************************************************************/
#include "kbRGB.h"
#include <math.h>
/*************************************************************************************************\
|        ColorWheel [9]                                                                           |
\*************************************************************************************************/
void kbRGB_ColorWheel_Init(void)       // 色轮
{
    kbrgb_Params.Speed = 100;
    kbrgb_Params.Slider2Val = 50;
}
#if 0
uint32_t ColorWheelEffect_GetColor(unsigned int x, unsigned int y, double cx, double cy, int reverse)
{
    float direction_mult = -1.0f;//direction == 0 ? 1.f : -1.f;
    float hue = (float)(kbrgb_Params.progress + (int)(180 + direction_mult * (reverse ? atan2(y - cy, x - cx) : atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    hsv_t hsv = { 0, 0, 0 };
    hsv.hue = (int)hue;
    hsv.saturation = 255;
    hsv.value = 255;

    return (hsv2rgb(&hsv));
}
#else
static uint32_t ColorWheelEffect_GetColor(const uint16_t x, const uint16_t y, const double cx, const double cy, const double progress, const int reverse)
{
    //float direction_mult = -1.0f;//direction == 0 ? 1.f : -1.f;
    double angle;
    struct kbRGB_Pixel piont;
    float hue;// = (float)(progress + (int)(180 + direction_mult * (reverse ? atan2(y - cy, x - cx) : atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    piont.pixel = kbRGB_AngleGet((x - cx), (y - cy));
    angle = piont.angle/8.0f;
    //hue = (float)(progress + (int)(180 + direction_mult * (reverse ? atan2(y - cy, x - cx) : atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    hue = (float)(progress + (int)(360 + /*direction_mult **/(reverse ? angle : 90.0f-angle)) % 360);
    //hue = (float)(progress + (int)(180 + (atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    //hue = (float)(progress + (int)(360 - angle) % 360);
    hsv_t hsv = { 0, 0, 0 };
    hsv.hue = (int)hue;
    hsv.saturation = 255;
    hsv.value = 255;

    return (hsv2rgb(&hsv));
}
#endif
void kbRGB_ColorWheel(const uint16_t cols, const uint16_t rows)       // 色轮
{
    float cx_shift_mult = 0.5f;//cx_shift / 100.f;
    float cy_shift_mult = 0.5f;//cy_shift / 100.f;
    double cx = (cols - 1) * cx_shift_mult;
    double cy = (rows - 1) * cy_shift_mult;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
         for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = ColorWheelEffect_GetColor(col_id, row_id, cx, cy, kbRGB_progress, 0);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_progress += (float) kbRGB_Speed / (float) kbRGB_FPS;
}

/*************************************************************************************************\
|        DoubleRotatingRainbow [9]                                                                              |
\*************************************************************************************************/
void kbRGB_DoubleRotatingRainbow_Init(void)       // 双旋转彩虹
{
    kbrgb_Params.Speed = 50;
    kbrgb_Params.Slider2Val = 20;
    kbrgb_Params.Rainbow.frequency = 10;
}
static uint32_t DoubleRotatingRainbow_GetColor(const uint16_t x, const uint16_t y, const float cx, const float cy, const int32_t angle, int frequency, const int reverse)
{
//    double c = reverse? kbrgb_Params.cos_reverse_time : kbrgb_Params.cos_time;
//    double s = reverse? kbrgb_Params.sin_reverse_time : kbrgb_Params.sin_time;
//    double c = reverse? cos(-kbrgb_Params.time) : cos(kbrgb_Params.time);
//    double s = reverse? sin(-kbrgb_Params.time) : sin(kbrgb_Params.time);
    double c = reverse? kbRGB_Cos(-angle) : kbRGB_Cos(angle);
    double s = reverse? kbRGB_Sin(-angle) : kbRGB_Sin(angle);
    c = c / kbRGB_SinMax;
    s = s / kbRGB_SinMax;

    hsv_t hsv;

    hsv.hue = (int)(kbRGB_time * kbrgb_Params.Slider2Val + 360 * (frequency * (y - cy) * c + (56 - fabs(x - cx)) * frequency * s) / 128.0) % 360;
    hsv.value = 255;
    hsv.saturation = 255;

    return (hsv2rgb(&hsv));
}
void kbRGB_DoubleRotatingRainbow(const uint16_t cols, const uint16_t rows)       // 双旋转彩虹
{
    const int32_t angle = kbRGB_time*180/KBRGB_PI;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
           uint32_t color = DoubleRotatingRainbow_GetColor(col_id, row_id, (cols - 1) * 0.5, (rows - 1) * 0.5, angle, kbrgb_Params.Rainbow.frequency, 0);
           kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_time += 0.01 * kbRGB_Speed / (float) kbRGB_FPS;
//    kbrgb_Params.cos_time = cos(kbrgb_Params.time);
//    kbrgb_Params.sin_time = sin(kbrgb_Params.time);
//    kbrgb_Params.cos_reverse_time = cos(-kbrgb_Params.time);
//    kbrgb_Params.sin_reverse_time = sin(-kbrgb_Params.time);
}

/*************************************************************************************************\
|        Hypnotoad [9]                                                                              |
\*************************************************************************************************/
//static float animation_speed = 10.f;
//static float color_rotation_speed = 50.f;
//static unsigned int animation_direction = 0;
//static unsigned int color_rotation_direction = 0;
//static unsigned int spacing = 1;
//static unsigned int thickness = 1;
//static unsigned int cx_shift = 50;
//static unsigned int cy_shift = 50;
void kbRGB_Hypnotoad_Init(void)                  // Hypnotoad
{
    kbrgb_Params.Speed = 50;
    kbrgb_Params.Slider2Val = 50;
    kbRGB_progress = 1000.f;
    kbrgb_Params.RainbowHypn.animation_speed = 10.f;
    kbrgb_Params.RainbowHypn.color_rotation_speed = 50.f;
    kbrgb_Params.RainbowHypn.animation_direction = 0;
    kbrgb_Params.RainbowHypn.color_rotation_direction = 0;
    kbrgb_Params.RainbowHypn.spacing = 1;
    kbrgb_Params.RainbowHypn.thickness = 1;
}
static uint32_t Hypnotoad_GetColor(const uint16_t x, const uint16_t y, const float cx, const float cy, const int reverse)
{
    float animation_mult = 0.01 * (reverse ? -1.0 : 1.0) * kbrgb_Params.RainbowHypn.animation_speed * (kbrgb_Params.RainbowHypn.animation_direction == 0 ? 1 : -1);
    float color_mult = 0.01 * (reverse ? -1.0 : 1.0) * kbrgb_Params.RainbowHypn.color_rotation_speed * (kbrgb_Params.RainbowHypn.color_rotation_direction == 0 ? -1 : 1);

//    double angle    = atan2(y - cy, x - cx) * 180 / 3.14159265359;
    double distance = sqrt(pow(cx - x, 2) + pow(cy - y, 2));
    struct kbRGB_Pixel piont;
    piont.pixel = kbRGB_AngleGet((x - cx), (y - cy));
    double angle    = piont.angle>>KBRGB_ANGLE_PRE;
    //double distance = piont.radius*0.5f;
    float  value    = cos(animation_mult * distance / (0.1 * (float) kbrgb_Params.RainbowHypn.spacing)  + kbRGB_progress);

    hsv_t hsv;
    hsv.value = pow((value + 1) * 0.5, (11 - kbrgb_Params.RainbowHypn.thickness)) * 255;
    hsv.hue = abs((int)(angle + distance + kbRGB_progress * color_mult * kbrgb_Params.RainbowHypn.color_rotation_speed) % 360);
    hsv.saturation = 255;
    hsv.value = (value + 1) * 0.5 * 255;
    //hsv.saturation = (value + 1) * 0.5 * 255;

    return (hsv2rgb(&hsv));
}
void kbRGB_Hypnotoad(const uint16_t cols, const uint16_t rows)                  // Hypnotoad
{
    float cx_shift_mult = 0.5f;//cx_shift / 100.f;
    float cy_shift_mult = 0.5f;//cy_shift / 100.f;
    unsigned int width = cols;
    unsigned int height = rows;

    float cx = (width-1) * cx_shift_mult;
    float cy = (height-1) * cy_shift_mult;

    int reverse=1;
    for(uint16_t row_id = 0; row_id < height; row_id++)
    {
        for(uint16_t col_id = 0; col_id <  width; col_id++)
        {
            uint32_t color = Hypnotoad_GetColor(col_id, row_id, cx, cy, reverse);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_progress +=  0.1 * (float) kbRGB_Speed / (float) kbRGB_FPS;
}

/*************************************************************************************************\
|        NoiseMap [9]                                                                             |
\*************************************************************************************************/
//struct SimplexNoise {
//    // Parameters of Fractional Brownian Motion (fBm) : sum of N "octaves" of noise
//    float mFrequency;   ///< Frequency ("width") of the first octave of noise (default to 1.0)
//    float mAmplitude;   ///< Amplitude ("height") of the first octave of noise (default to 1.0)
//    float mLacunarity;  ///< Lacunarity specifies the frequency multiplier between successive octaves (default to 2.0).
//    float mPersistence; ///< Persistence is the loss of amplitude between successive octaves (usually 1/lacunarity)
//};
static const float frequency = 0.12;
static const float amplitude = 3.9;
static const float lacunarity = 0.75;
static const float persistence = 0.5;
//static int octaves = 2;
//static int motion = 0;
//static int motion_speed = 1;
//static struct SimplexNoise_t Noise;
#define octaves      kbrgb_Params.Rainbow_NoiseMap.octaves
#define motion       kbrgb_Params.Rainbow_NoiseMap.motion
#define motion_speed kbrgb_Params.Rainbow_NoiseMap.motion_speed
#define Noise        kbrgb_Params.Rainbow_NoiseMap.Noise
void kbRGB_NoiseMap_Init(void)                   // 噪声地图
{
    kbrgb_Params.Speed = 50;
    kbrgb_Params.Slider2Val = 50;
    //ResetNoise();
    octaves = 2;
    motion = 0;
    motion_speed = 1;
    SimplexNoise_Init(&Noise, frequency, amplitude, lacunarity, persistence);
    //ResetColors();
}


static uint32_t NoiseMap_GetColor(unsigned int x, unsigned int y)
{
    float x_shift = 0;
    float y_shift = 0;

    switch (motion) {

    case 0: y_shift = motion_speed * kbRGB_progress; break;
    case 1: y_shift = motion_speed * -kbRGB_progress;  break;
    case 2: x_shift = motion_speed * kbRGB_progress;  break;
    case 3: x_shift = motion_speed * -kbRGB_progress;  break;

    default: break;
    }


    float value = SimplexNoise_fractal3d(&Noise, octaves, x + x_shift, y + y_shift, kbRGB_progress);
    float frac = (1+value)*0.5;

    int color_choice = 0;//ui->colors_choice->currentIndex();
    hsv_t hsv;

    switch (color_choice)
    {
    case 0:
        hsv.hue = 360 * frac;
        hsv.saturation = 255;
        hsv.value = 255 ;
        return (hsv2rgb(&hsv));

    case 1:
        hsv.hue = 360 - 360 * frac;
        hsv.saturation = 255;
        hsv.value = 255 ;
        return (hsv2rgb(&hsv));

//    case 2:
//        int color_x = (1 - frac) * 100;
//        QColor c = image.pixelColor(color_x, 0);
//        return ColorUtils::fromQColor(c);
    }

    //return ColorUtils::OFF();
    return 0x00;
}
void kbRGB_NoiseMap(const uint16_t cols, const uint16_t rows)                   // 噪声地图
{
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = NoiseMap_GetColor(col_id, row_id);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_progress +=  0.1 * (float) kbRGB_Speed / (float) kbRGB_FPS;
}

/*************************************************************************************************\
|        NoiseCircle [9]                                                                             |
\*************************************************************************************************/
void kbRGB_NoiseCircle_Init(void)                // 噪声地图
{
    kbrgb_Params.Speed = 150;
    kbrgb_Params.Slider2Val = 50;
    octaves = 2;
    motion = 0;
    motion_speed = 1;
    //SimplexNoise_Init(&Noise, frequency, amplitude, lacunarity, persistence);
    SimplexNoise_Init(&Noise, frequency/5.5, amplitude, lacunarity/5.0, persistence);
}
static uint32_t NoiseCircle_GetColor(const uint16_t x, const uint16_t y, const int32_t cx, const int32_t cy)
{
    float x_shift = 0;
    float y_shift = 0;

    struct kbRGB_Pixel piont;
    piont.pixel = kbRGB_AngleGet((x - cx), (y - cy));

    switch (motion) {

    case 0: y_shift = motion_speed * kbRGB_progress; break;
    case 1: y_shift = motion_speed * -kbRGB_progress;  break;
    case 2: x_shift = motion_speed * kbRGB_progress;  break;
    case 3: x_shift = motion_speed * -kbRGB_progress;  break;

    default: break;
    }

    double angle = piont.angle/8.0f;
    angle = angle*KBRGB_PI/180;
    double distance = sqrt(pow(cx - x, 2) + pow(cy - y, 2));
    float value = SimplexNoise_fractal2d(&Noise, octaves, distance*0.5, kbRGB_progress);
    //float value = SimplexNoise_fractal2d(&Noise, octaves, distance, kbRGB_progress+angle/2.0f);
    //float value = SimplexNoise_fractal2d(&Noise, octaves, angle, kbRGB_progress+angle);
    //float value = SimplexNoise_fractal2d(&Noise, octaves, angle, kbRGB_progress+distance);
    //if(angle<0) angle=-angle; float value = SimplexNoise_fractal2d(&Noise, octaves, (distance+x)/(angle+3.5f+y), kbRGB_progress+angle);
    //float value = SimplexNoise_fractal2d(&Noise, octaves, angle, kbRGB_progress+angle/(distance+1));
    //if(angle<0) angle=-angle; float value = SimplexNoise_fractal2d(&Noise, octaves, angle, kbRGB_progress+(distance*angle)/(angle+1.5));
    //if(angle<0) angle=-angle; float value = SimplexNoise_fractal(&Noise, octaves, kbRGB_progress+(distance*angle)/(angle+1.5));
    //if(angle<0) angle=-angle; float value = SimplexNoise_fractal(&Noise, octaves, kbRGB_progress+(distance*angle+x)/(angle+1.5));
    //if(angle<0) angle=-angle; float value = SimplexNoise_fractal(&Noise, octaves, kbRGB_progress+(distance)/(angle+1.5));
    float frac = (1+value)*0.5;

    int color_choice = 0;//ui->colors_choice->currentIndex();
    hsv_t hsv;

    switch (color_choice)
    {
    case 0:
        hsv.hue = 360 * frac;
        //hsv.hue = (distance+0)*50/(angle+8.5f+0)+(kbRGB_progress+angle+(x+0)/(distance+3.0f))*30;
        hsv.hue = hsv.hue%360;
        hsv.saturation = 255;
        hsv.value = 255 ;
        return (hsv2rgb(&hsv));

    case 1:
        hsv.hue = 360 - 360 * frac;
        hsv.saturation = 255;
        hsv.value = 255 ;
        return (hsv2rgb(&hsv));

//    case 2:
//        int color_x = (1 - frac) * 100;
//        QColor c = image.pixelColor(color_x, 0);
//        return ColorUtils::fromQColor(c);
    }

    //return ColorUtils::OFF();
    return 0x00;
}
void kbRGB_NoiseCircle(const uint16_t cols, const uint16_t rows)        // 噪声地图
{
    int32_t cx = ((cols<<0) - 1)>>1;// * 0.5;
    int32_t cy = ((rows<<0) - 1)>>1;// * 0.5;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = NoiseCircle_GetColor(col_id, row_id, cx, cy);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_progress +=  0.1 * (float) kbRGB_Speed / (float) kbRGB_FPS;
}

/*************************************************************************************************\
|        RainbowWave [9]                                                                          |
\*************************************************************************************************/
void kbRGB_RainbowWave_Init(void)       // 彩虹波
{
    kbrgb_Params.Speed = 40;
    kbrgb_Params.Slider2Val = 10;
}
void kbRGB_RainbowWave(const uint16_t cols, const uint16_t rows)       // 彩虹波
{
    int Width = kbrgb_Params.Slider2Val;

    hsv_t HSVVal;
    HSVVal.saturation = 255;
    HSVVal.value      = 255;
    //int ColumnCount = cols;
    //int RowCount = rows;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        int HUE;
        int RVRS = 0;

        if (RVRS)
        {
            HUE = ((kbRGB_progress + (int)( (cols - 1) - col_id)) * Width);
        }
        else
        {
            HUE = ((kbRGB_progress + (int)col_id) * Width);
        }

        HSVVal.hue = HUE;

        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            kbRGB_pset(col_id, row_id, hsv2rgb(&HSVVal));
        }
    }
    if (kbRGB_progress < 360)
    {
        kbRGB_progress += (((float)kbRGB_Speed) / ((float)kbRGB_FPS));
    }
    else if (kbRGB_progress >= 360)
    {
        kbRGB_progress = 0;
    }
}

/*************************************************************************************************\
|        Rainbow [9]                                                                              |
\*************************************************************************************************/
static uint32_t RadialRainbow_GetColor(const uint16_t x, const uint16_t y, const int16_t cx, const int16_t cy, const int reverse)
{
    hsv_t hsv;
    float width = kbRGB_Slider2Val * 0.5f;
    double distance, distance2;
    struct kbRGB_Pixel piont;

    if(kbrgb_Params.Rainbow.shape == 0)
    {
        //distance = sqrt(pow(cx - x, 2) + pow(cy - y, 2));
        piont.pixel = kbRGB_AngleGet((x - cx), (y - cy));
        distance = piont.radius;
    }
    else if (kbrgb_Params.Rainbow.shape == 1)
    {
        //distance = std::max<float>(fabs(cy - y), fabs(cx - x));
        distance = fabs(cy - y);
        distance2 = fabs(cx - x);
        if(distance<distance2) distance=distance2;
    }
    else
    {
        return 0x00;//ColorUtils::OFF();
    }

    hsv.hue = distance * width + (reverse ? kbRGB_progress:-kbRGB_progress);
    hsv.hue %= 360;

    hsv.saturation = 255;
    hsv.value = 255;

    return (hsv2rgb(&hsv));
}
void kbRGB_RadialRainbow_Init(void)       // 径向彩虹
{
    kbrgb_Params.Speed = 100;
    kbrgb_Params.Slider2Val = 50;
    kbrgb_Params.Rainbow.shape = 1;
}
void kbRGB_RadialRainbow(const uint16_t cols, const uint16_t rows)       // 径向彩虹
{
    float cx_shift_mult = 0.5f;//cx_shift / 100.f;
    float cy_shift_mult = 0.5f;//cy_shift / 100.f;
    double cx = (cols - 1) * cx_shift_mult;
    double cy = (rows - 1) * cy_shift_mult;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = RadialRainbow_GetColor(col_id, row_id, cx, cy, 0);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_progress += (float) kbRGB_Speed / (float) kbRGB_FPS;
}

/*************************************************************************************************\
|        RotatingRainbow [9]                                                                      |
\*************************************************************************************************/
void kbRGB_RotatingRainbow_Init(void)       // 旋转的彩虹
{
    kbrgb_Params.Speed = 20;
    kbrgb_Params.Slider2Val = 30;
}
static uint32_t RotatingRainbow_GetColor(const uint16_t x, const uint16_t y, const int16_t cx, const int32_t cy, const int32_t angle, const int reverse)
{
//    double c = reverse? cos_reverse_time : cos_time;
//    double s = reverse? sin_reverse_time : sin_time;
//    double c = reverse? cos(-kbrgb_Params.time) : cos(kbrgb_Params.time);
//    double s = reverse? sin(-kbrgb_Params.time) : sin(kbrgb_Params.time);
    double c = reverse? kbRGB_Cos(-angle) : kbRGB_Cos(angle);
    double s = reverse? kbRGB_Sin(-angle) : kbRGB_Sin(angle);
    c = c/(float)kbRGB_SinMax;
    s = s/(float)kbRGB_SinMax;

    hsv_t hsv;

    hsv.hue = (int)(kbRGB_time * kbRGB_Slider2Val + 360 * ((y - cy) * 2 * c + (x - cx) * 2 * s) / 128) % 360;
    hsv.value = 255;
    hsv.saturation = 255;

    return (hsv2rgb(&hsv));
}

void kbRGB_RotatingRainbow(const uint16_t cols, const uint16_t rows)       // 旋转的彩虹
{
    float cx = (cols - 1) * 0.5;
    float cy = (rows - 1) * 0.5;
    int16_t angle = kbRGB_time*180/KBRGB_PI;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
           uint32_t color = RotatingRainbow_GetColor(col_id, row_id, cx, cy, angle, 0);
           kbRGB_pset(col_id, row_id, color);
        }
    }
    kbRGB_time += 0.1 * kbRGB_Speed / (float) kbRGB_FPS;

//    cos_time = cos(kbrgb_Params.time);
//    sin_time = sin(kbrgb_Params.time);

//    cos_reverse_time = cos(-kbrgb_Params.time);
//    sin_reverse_time = sin(-kbrgb_Params.time);
}

/*************************************************************************************************\
|        SpectrumCycling [9]                                                                      |
\*************************************************************************************************/
void kbRGB_SpectrumCycling_Init(void)       // 光谱骑自行车
{
    kbrgb_Params.Speed = 50;
    kbrgb_Params.Slider2Val = 30;
}
void kbRGB_SpectrumCycling(const uint16_t cols, const uint16_t rows)       // 光谱骑自行车
{
    hsv_t HSVVal;

    HSVVal.value = 255;
    HSVVal.saturation = 255;
    HSVVal.hue = ((int)kbRGB_progress) % 360;

    uint32_t color = (hsv2rgb(&HSVVal));

    //for(ControllerZone* controller_zone: controller_zones)
//    {
//        controller_zone->SetAllZoneLEDs(color, Brightness);
//    }
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
           kbRGB_pset(col_id, row_id, color);
        }
    }

    kbRGB_progress += (float) kbRGB_Speed / (float) kbRGB_FPS;
}

